package com.cyanite.playlv2api;

import com.cyanite.playlv2api.error.PlayLv2ApiCredentialsException;
import com.cyanite.playlv2api.error.PlayLv2ApiError;
import com.cyanite.playlv2api.error.PlayLv2ApiException;
import com.cyanite.playlv2api.error.PlayLv2ApiParseException;
import com.cyanite.playlv2api.http.AbstractHttpApi;
import com.cyanite.playlv2api.http.HttpApi;
import com.cyanite.playlv2api.http.HttpApiWithBasicAuth;
import com.cyanite.playlv2api.parsers.json.TipParser;
import com.cyanite.playlv2api.parsers.json.TripMiniParser;
import com.cyanite.playlv2api.parsers.json.VenueCategoryParser;
import com.cyanite.playlv2api.parsers.json.CheckinParser;
import com.cyanite.playlv2api.parsers.json.CheckinResultParser;
import com.cyanite.playlv2api.parsers.json.CityParser;
import com.cyanite.playlv2api.parsers.json.FriendInvitesResultParser;
import com.cyanite.playlv2api.parsers.json.GroupParser;
import com.cyanite.playlv2api.parsers.json.MessageParser;
import com.cyanite.playlv2api.parsers.json.PhotoParser;
import com.cyanite.playlv2api.parsers.json.ResponseParser;
import com.cyanite.playlv2api.parsers.json.TaskMiniParser;
import com.cyanite.playlv2api.parsers.json.SecretParser;
import com.cyanite.playlv2api.parsers.json.SettingsParser;
import com.cyanite.playlv2api.parsers.json.TaskCategoryParser;
import com.cyanite.playlv2api.parsers.json.TaskParser;
import com.cyanite.playlv2api.parsers.json.UserParser;
import com.cyanite.playlv2api.parsers.json.VenueParser;
import com.cyanite.playlv2api.parsers.json.TripParser;
import com.cyanite.playlv2api.types.Tip;
import com.cyanite.playlv2api.types.TripMini;
import com.cyanite.playlv2api.types.VenueCategory;
import com.cyanite.playlv2api.types.Checkin;
import com.cyanite.playlv2api.types.CheckinResult;
import com.cyanite.playlv2api.types.City;
import com.cyanite.playlv2api.types.FriendInvitesResult;
import com.cyanite.playlv2api.types.Group;
import com.cyanite.playlv2api.types.Message;
import com.cyanite.playlv2api.types.Photo;
import com.cyanite.playlv2api.types.Response;
import com.cyanite.playlv2api.types.TaskMini;
import com.cyanite.playlv2api.types.Secret;
import com.cyanite.playlv2api.types.Settings;
import com.cyanite.playlv2api.types.Task;
import com.cyanite.playlv2api.types.TaskCategory;
import com.cyanite.playlv2api.types.User;
import com.cyanite.playlv2api.types.Venue;
import com.cyanite.playlv2api.types.Trip;
import com.cyanite.playlv2api.util.JSONUtils;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import android.graphics.Bitmap;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;

class PlayLv2HttpApi {

    //private static final String URL_API_VENUES = "http://api.foursquare.com/v1/venues.json";
    private static final String URL_API_LOGIN = "/index.php?lang=zh_cn&m=do&c=login";
    private static final String URL_API_SIGNUP = "/index.php?lang=zh_cn&m=do&c=register";
    private static final String URL_API_BIND_BLOG = "/index.php?lang=zh_cn&m=do&c=bindBlog";
    private static final String URL_API_TRIPS = "/index.php?lang=zh_cn&m=trips&c=list";
    private static final String URL_API_TASK_CATEGORIES = "/index.php?lang=zh_cn&m=tasks&c=list";
    private static final String URL_API_TASKS = "/index.php?lang=zh_cn&m=record&c=list";
    private static final String URL_API_TIPS = "/index.php?lang=zh_cn&m=tips&c=list";
    private static final String URL_API_SECRETS = "/index.php?lang=zh_cn&m=games&c=treasure";
    private static final String URL_API_TRIP = "/index.php?lang=zh_cn&m=trips&c=detail";
    private static final String URL_API_TRIP_FOCUSED = "/index.php?lang=zh_cn&m=trips&c=focus";
    private static final String URL_API_TRIP_ADD_FOLLOWED = "/index.php?lang=zh_cn&m=trips&c=publish";
    private static final String URL_API_USER = "/index.php?lang=zh_cn&m=members&c=detail";
    private static final String URL_API_TRIP_CREATE = "/index.php?lang=zh_cn&m=trips&c=publish";
    private static final String URL_API_FRIEND_SENDREQUEST = "/index.php?lang=zh_cn&m=friends&c=publish";
    private static final String URL_API_FIND_FRIENDS_BY_INPUT = "/index.php?lang=zh_cn&m=friends&c=search";
    private static final String URL_API_FRIEND_REQUESTS = "/index.php?lang=zh_cn&m=friends&c=publish";
    private static final String URL_API_FRIENDS = "/index.php?lang=zh_cn&m=friends&c=search";
    private static final String URL_API_EMAIL_REQUEST = "/index.php?lang=zh_cn&m=email&c=publish";
    private static final String URL_API_MESSAGES = "/index.php?lang=zh_cn&m=pms&c=list";
    private static final String URL_API_MESSAGE = "/index.php?lang=zh_cn&m=pms&c=publish";
    private static final String URL_API_VENUES = "/index.php?lang=zh_cn&m=venues&c=list";
    private static final String URL_API_USER_PHOTO_UPDATE = "/index.php?lang=zh_cn&m=members&c=avatar&act=upload&uid=%s&file_ext=%s";
    private static final String URL_API_PHOTO_UPLOAD = "/index.php?lang=zh_cn&m=checkin&c=publish&act=upload&uid=%s&file_ext=%s";
    private static final String URL_API_ADDTIP = "/index.php?lang=zh_cn&m=tips&c=publish";
    private static final String URL_API_CHECKIN = "/index.php?lang=zh_cn&m=checkin&c=publish";
    private static final String URL_API_ADDVENUE = "/addvenue";
    private static final String URL_API_CITIES = "/cities";
    private static final String URL_API_CHECKINS = "/checkins";

    private static final String URL_API_FIND_FRIENDS_BY_NAME = "/findfriends/byname";
    private static final String URL_API_FIND_FRIENDS_BY_PHONE = "/findfriends/byphone";
    private static final String URL_API_CATEGORIES = "/categories";
    private static final String URL_API_HISTORY = "/history";
    private static final String URL_API_FIND_FRIENDS_BY_PHONE_OR_EMAIL = "/findfriends/byphoneoremail";
    private static final String URL_API_INVITE_BY_EMAIL = "/invite/byemail";
    private static final String URL_API_SETPINGS = "/settings/setpings";
    private static final String URL_API_VENUE_FLAG_CLOSED = "/venue/flagclosed";
    private static final String URL_API_VENUE_FLAG_MISLOCATED = "/venue/flagmislocated";
    private static final String URL_API_VENUE_FLAG_DUPLICATE = "/venue/flagduplicate";
    private static final String URL_API_VENUE_PROPOSE_EDIT = "/venue/proposeedit";
    private static final String URL_API_TIP_DETAIL = "/tip/detail";

    private final DefaultHttpClient mHttpClient = AbstractHttpApi.createHttpClient();
    private HttpApi mHttpApi;

    private final String mApiBaseUrl;
    private final AuthScope mAuthScope;
    private String mAuthUserId;

    public PlayLv2HttpApi(String domain, String clientVersion) {
        mApiBaseUrl = "http://" + domain;
        mAuthScope = new AuthScope(domain, 80);
        mHttpApi = new HttpApiWithBasicAuth(mHttpClient, clientVersion);
    }

    public void setAuthUserId(String authUserId)    {
        mAuthUserId = authUserId;
    }

    void setCredentials(String phone, String password) {
        if (phone == null || phone.length() == 0 || password == null || password.length() == 0) {
            mHttpClient.getCredentialsProvider().clear();
        } else {
            mHttpClient.getCredentialsProvider().setCredentials(mAuthScope,
                    new UsernamePasswordCredentials(phone, password));
        }
    }

    public boolean hasCredentials() {
        return mHttpClient.getCredentialsProvider().getCredentials(mAuthScope) != null;
    }

    User login( String account, String passwd ) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_LOGIN),
                new BasicNameValuePair("account", account),
                new BasicNameValuePair("password", passwd),
                new BasicNameValuePair("p_act", "login"));
        return (User) mHttpApi.doHttpRequest(httpPost, new UserParser());
    }

    Response bindBlog( String account, String passwd ) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_BIND_BLOG),
                new BasicNameValuePair("account", account),
                new BasicNameValuePair("password", passwd),
                new BasicNameValuePair("p_act", "bind"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    User signup( String account, String passwd, String phone, String email, String gender,
                          String country, String province, String city, String street )
        throws PlayLv2ApiException, PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_SIGNUP),
                new BasicNameValuePair("username", account),
                new BasicNameValuePair("password", passwd),
                new BasicNameValuePair("email", email),
                new BasicNameValuePair("mobile", phone),
                new BasicNameValuePair("gender", gender),
                new BasicNameValuePair("country", country),
                new BasicNameValuePair("province", province),
                new BasicNameValuePair("city", city),
                new BasicNameValuePair("street", street),
                new BasicNameValuePair("p_act", "register"));
        return (User) mHttpApi.doHttpRequest(httpPost, new UserParser());
    }

    Response createTrip(String title, String startpoint, String endpoint,
            String starttime, String type, String days) throws PlayLv2ApiException, PlayLv2ApiError, IOException    {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIP_CREATE),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("name", title),
                new BasicNameValuePair("begin_address", startpoint),
                new BasicNameValuePair("end_address", endpoint),
                new BasicNameValuePair("day", days),
                new BasicNameValuePair("custom_name", type),
                new BasicNameValuePair("play_date", String.valueOf(starttime)),
                new BasicNameValuePair("access_pname", "Android"),
                new BasicNameValuePair("p_act", "create"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    Tip addtip(String vid, String text, String type, String geolat, String geolong, String geohacc,
            String geovacc, String geoalt) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_ADDTIP), //
                new BasicNameValuePair("vid", vid), //
                new BasicNameValuePair("text", text), //
                new BasicNameValuePair("type", type), //
                new BasicNameValuePair("geolat", geolat), //
                new BasicNameValuePair("geolong", geolong), //
                new BasicNameValuePair("geohacc", geohacc), //
                new BasicNameValuePair("geovacc", geovacc), //
                new BasicNameValuePair("geoalt", geoalt));
        return (Tip) mHttpApi.doHttpRequest(httpPost, new TipParser());
    }

    Response addTip(String vid, String categoryId, String text, int categoryType) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        String param = "";
        switch (categoryType)   {
            case 0: // tripId
                param = "trip_id";
                break;
            case 1: // venueId
                param = "venue_id";
                break;
            case 2: // taskId
                param = "task_id";
                break;
        }
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_ADDTIP), //
                new BasicNameValuePair("view_uid", vid),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("content", text),
                new BasicNameValuePair(param, categoryId),
                new BasicNameValuePair("access_pname", "Android"),
                new BasicNameValuePair("p_act", "create"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    /**
     * @param name the name of the venue
     * @param address the address of the venue (e.g., "202 1st Avenue")
     * @param crossstreet the cross streets (e.g., "btw Grand & Broome")
     * @param city the city name where this venue is
     * @param state the state where the city is
     * @param zip (optional) the ZIP code for the venue
     * @param phone (optional) the phone number for the venue
     * @return
     * @throws PlayLv2ApiException
     * @throws PlayLv2ApiCredentialsException
     * @throws PlayLv2ApiError
     * @throws IOException
     */
    Venue addvenue(String name, String address, String crossstreet, String city, String state,
            String zip, String phone, String categoryId, String geolat, String geolong, String geohacc,
            String geovacc, String geoalt) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_ADDVENUE), //
                new BasicNameValuePair("name", name), //
                new BasicNameValuePair("address", address), //
                new BasicNameValuePair("crossstreet", crossstreet), //
                new BasicNameValuePair("city", city), //
                new BasicNameValuePair("state", state), //
                new BasicNameValuePair("zip", zip), //
                new BasicNameValuePair("phone", phone), //
                new BasicNameValuePair("primarycategoryid", categoryId), //
                new BasicNameValuePair("geolat", geolat), //
                new BasicNameValuePair("geolong", geolong), //
                new BasicNameValuePair("geohacc", geohacc), //
                new BasicNameValuePair("geovacc", geovacc), //
                new BasicNameValuePair("geoalt", geoalt) //
                );
        return (Venue) mHttpApi.doHttpRequest(httpPost, new VenueParser());
    }

    /*
     * /cities
     */
    @SuppressWarnings("unchecked")
    Group<City> cities() throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpGet httpGet = mHttpApi.createHttpGet(fullUrl(URL_API_CITIES));
        return (Group<City>) mHttpApi.doHttpRequest(httpGet, new GroupParser(new CityParser()));
    }

    @SuppressWarnings("unchecked")
    Group<TaskMini> searchTask(String query,
            String searchCategory) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TASKS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("srch_keys", query),
                new BasicNameValuePair("srch_venue_cat_id", "0"),
                new BasicNameValuePair("p_act", "search_checkin"));
        return (Group<TaskMini>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TaskMiniParser()));
    }
    @SuppressWarnings("unchecked")
    Group<TripMini> searchTrip(String query,
            String searchCategory) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIPS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("srch_keys", query),
                new BasicNameValuePair("srch_type", searchCategory),
                new BasicNameValuePair("p_act", "search_trips"));
        return (Group<TripMini>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TripMiniParser()));
    }
    @SuppressWarnings("unchecked")
    Group<Trip> trips(String viewUserId, String process) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIPS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", viewUserId),
                new BasicNameValuePair("srch_type", process),
                new BasicNameValuePair("p_act", "me_list"));
        return (Group<Trip>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TripParser()));
    }

    @SuppressWarnings("unchecked")
    Group<Trip> tripsHot(int tripsPage) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIPS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("page", String.valueOf(tripsPage)),
                new BasicNameValuePair("p_act", "hot"));
        return (Group<Trip>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TripParser()));
    }

    public Response deleteTrip(String tripId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIP_CREATE), //
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("trip_id", tripId),
                new BasicNameValuePair("p_act", "delete"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    @SuppressWarnings("unchecked")
    Group<TaskCategory> taskcategories(String tripId) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TASK_CATEGORIES),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("trip_id", tripId),
                new BasicNameValuePair("p_act", "list"));
        return (Group<TaskCategory>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TaskCategoryParser()));
    }

    @SuppressWarnings("unchecked")
    Group<Task> tasks(String viewUserId, String taskcatId) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TASKS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", viewUserId),
                new BasicNameValuePair("task_id", taskcatId),
                new BasicNameValuePair("p_act", "tasks"));
        return (Group<Task>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TaskParser()));
    }

    @SuppressWarnings("unchecked")
    Group<Task> tasks(String tripId) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIPS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("t_id", tripId),
                new BasicNameValuePair("p_act", "checkin_list"));
        return (Group<Task>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TaskParser()));
    }

    @SuppressWarnings("unchecked")
    Group<Task> tasksFocused(int tasksPage) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TASKS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("page", String.valueOf(tasksPage)),
                new BasicNameValuePair("p_act", "me_focus"));
        return (Group<Task>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TaskParser()));
    }
    
    @SuppressWarnings("unchecked")
    Group<Task> tasksArounded(double latitude, double longitude) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TASKS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("srch_map_lat", String.valueOf(latitude)),
                new BasicNameValuePair("srch_map_lng", String.valueOf(longitude)),
                new BasicNameValuePair("p_act", "perimeter"));
        return (Group<Task>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TaskParser()));
    }

    @SuppressWarnings("unchecked")
    Group<Secret> secrets(String viewUserId) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_SECRETS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", viewUserId),
                new BasicNameValuePair("p_act", "list"));
        return (Group<Secret>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new SecretParser()));
    }

    Response createSecret(String title, String content, String photoId, String geolat, String geolong,
            String secretLevel, String cost, String userIdsList) throws PlayLv2ApiException, PlayLv2ApiError, IOException    {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_SECRETS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("title", title),
                new BasicNameValuePair("pic_id", photoId),
                new BasicNameValuePair("content", content),
                new BasicNameValuePair("map_lat", geolat),
                new BasicNameValuePair("map_lng", geolong),
                new BasicNameValuePair("donkey_coin", cost),
                new BasicNameValuePair("role_type", secretLevel),
                new BasicNameValuePair("str_uid", userIdsList),
                new BasicNameValuePair("p_act", "create"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    Secret secret(String secretId) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_SECRETS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("t_id", secretId),
                new BasicNameValuePair("p_act", "view"));
        return (Secret) mHttpApi.doHttpRequest(httpPost, new SecretParser());
    }

    @SuppressWarnings("unchecked")
    Group<Tip> tips(String taskId) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TIPS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("srch_task_id", taskId),
                new BasicNameValuePair("p_act", "list"));
        return (Group<Tip>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new TipParser()));
    }

    Trip trip(String tripId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIP), //
                new BasicNameValuePair("trip_id", tripId),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("p_act", "detail"));
        return (Trip) mHttpApi.doHttpRequest(httpPost, new TripParser());
    }

    @SuppressWarnings("unchecked")
    Group<Photo> tripPhotos(String tripId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TASK_CATEGORIES), //
                new BasicNameValuePair("trip_id", tripId),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("p_act", "pics"));
        return (Group<Photo>) mHttpApi.doHttpRequest(httpPost, new GroupParser(
                new PhotoParser()));
    }

    @SuppressWarnings("unchecked")
    Group<Checkin> checkins(String geolat, String geolong, String geohacc, String geovacc,
            String geoalt) throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        HttpGet httpGet = mHttpApi.createHttpGet(fullUrl(URL_API_CHECKINS), //
                new BasicNameValuePair("geolat", geolat), //
                new BasicNameValuePair("geolong", geolong), //
                new BasicNameValuePair("geohacc", geohacc), //
                new BasicNameValuePair("geovacc", geovacc), //
                new BasicNameValuePair("geoalt", geoalt));
        return (Group<Checkin>) mHttpApi.doHttpRequest(httpGet,
                new GroupParser(new CheckinParser()));
    }

    CheckinResult checkin(String vid, String venue, String geolat, String geolong, String geohacc,
            String geovacc, String geoalt, String shout, boolean isPrivate, boolean tellFollowers)
        throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_CHECKIN), //
                new BasicNameValuePair("vid", vid), //
                new BasicNameValuePair("venue", venue), //
                new BasicNameValuePair("geolat", geolat), //
                new BasicNameValuePair("geolong", geolong), //
                new BasicNameValuePair("geohacc", geohacc), //
                new BasicNameValuePair("geovacc", geovacc), //
                new BasicNameValuePair("geoalt", geoalt), //
                new BasicNameValuePair("shout", shout), //
                new BasicNameValuePair("private", (isPrivate) ? "1" : "0"), //
                new BasicNameValuePair("followers", (tellFollowers) ? "1" : "0"), //
                new BasicNameValuePair("markup", "android")); // used only by android for checkin result 'extras'.
        return (CheckinResult) mHttpApi.doHttpRequest(httpPost, new CheckinResultParser());
    }

    Response share(Task task, String validateGps) throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        String content = "";
        if (task.getInfo() != null && task.getInfo().getInfoCount() > 0) {
            if ( task.getInfo().getInfoCount() == 1)    {
                content = "s{c}" + task.getInfo().getInfo1();
            } else if (task.getInfo().getInfoCount() == 2){
                content = "s{c}" + task.getInfo().getInfo1() + "{p}";
                content += "s{c}" + task.getInfo().getInfo2();
            }  else if (task.getInfo().getInfoCount() == 3){
                content = "s{c}" + task.getInfo().getInfo1() + "{p}";
                content += "s{c}" + task.getInfo().getInfo2() + "{p}";
                content += "s{c}" + task.getInfo().getInfo3();
            } else if (task.getInfo().getInfoCount() == 4){
                content = "s{c}" + task.getInfo().getInfo1() + "{p}";
                content += "s{c}" + task.getInfo().getInfo2() + "{p}";
                content += "s{c}" + task.getInfo().getInfo3() + "{p}";
                content += "s{c}" + task.getInfo().getInfo4();
            }  else if (task.getInfo().getInfoCount() == 5) {
                content = "s{c}" + task.getInfo().getInfo1() + "{p}";
                content += "s{c}" + task.getInfo().getInfo2() + "{p}";
                content += "s{c}" + task.getInfo().getInfo3() + "{p}";
                content += "s{c}" + task.getInfo().getInfo4() + "{p}";
                content += "s{c}" + task.getInfo().getInfo5();
            }
        }

        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_CHECKIN), //
                new BasicNameValuePair("uid", mAuthUserId), //
                new BasicNameValuePair("venue_name", task.getVenueName()), //
                new BasicNameValuePair("access_pname", "android"), //
                new BasicNameValuePair("task_id", task.getTaskCategoryId()), //
                new BasicNameValuePair("map_lat", task.getLatitude()), //
                new BasicNameValuePair("map_lng", task.getLongitude()), //
                new BasicNameValuePair("checkin_type", validateGps), //
                new BasicNameValuePair("pic_id", task.getPhotoId()), //
                new BasicNameValuePair("str_param", content), //
                new BasicNameValuePair("event_type", "1"), //
                new BasicNameValuePair("public_type", String.valueOf(task.getSecretLevel())),
                new BasicNameValuePair("p_act", "create"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    User user(String viewUserId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_USER),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", viewUserId),
                new BasicNameValuePair("p_act", "detail"));
        return (User) mHttpApi.doHttpRequest(httpPost, new UserParser());
    }

    User user(String uid, boolean badges, boolean stats, String geolat, String geolong,
            String geohacc, String geovacc, String geoalt) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_USER), //
                new BasicNameValuePair("uid", uid), //
                new BasicNameValuePair("badges", (badges) ? "1" : "0"), //
                new BasicNameValuePair("stats", (stats) ? "1" : "0"), //
                new BasicNameValuePair("geolat", geolat), //
                new BasicNameValuePair("geolong", geolong), //
                new BasicNameValuePair("geohacc", geohacc), //
                new BasicNameValuePair("geovacc", geovacc), //
                new BasicNameValuePair("geoalt", geoalt) //
                );
        return (User) mHttpApi.doHttpRequest(httpPost, new UserParser());
    }

    /**
     * /venues?geolat=37.770900&geolong=-122.43698
     */
    @SuppressWarnings("unchecked")
    Group<Venue> venues(String geolat, String geolong, String geohacc, String geovacc,
            String geoalt, String query, int limit, int scope) throws PlayLv2ApiException, PlayLv2ApiError,
            IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_VENUES), //
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("srch_map_lat", geolat), //
                new BasicNameValuePair("srch_map_lng", geolong), //
                //new BasicNameValuePair("geohacc", geohacc), //
                //new BasicNameValuePair("geovacc", geovacc), //
                //new BasicNameValuePair("geoalt", geoalt), //
                //new BasicNameValuePair("q", query), //
                //new BasicNameValuePair("l", String.valueOf(limit)),
                new BasicNameValuePair("p_act", "perimeter"),
                new BasicNameValuePair("srch_distance", String.valueOf(scope)),
                new BasicNameValuePair("srch_type", "venues"));
        return (Group<Venue>) mHttpApi.doHttpRequest(httpPost, new GroupParser(
                new VenueParser()));
    }

    /**
     * /venue?vid=1234
     */
    Venue venue(String vid, String geolat, String geolong, String geohacc, String geovacc,
            String geoalt) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_VENUES), //
                new BasicNameValuePair("uid", mAuthUserId), //
                new BasicNameValuePair("v_id", vid), //
                new BasicNameValuePair("p_act", "detail")//,
                //new BasicNameValuePair("geolat", geolat), //
                //new BasicNameValuePair("geolong", geolong), //
                //new BasicNameValuePair("geohacc", geohacc), //
                //new BasicNameValuePair("geovacc", geovacc), //
                //new BasicNameValuePair("geoalt", geoalt) //
                );
        return (Venue) mHttpApi.doHttpRequest(httpPost, new VenueParser());
    }

    /**
     * /tips?geolat=37.770900&geolong=-122.436987&l=1
     */
    @SuppressWarnings("unchecked")
    Group<Tip> tips(String geolat, String geolong, String geohacc, String geovacc,
            String geoalt, String uid, String filter, String sort, int limit) throws PlayLv2ApiException,
            PlayLv2ApiError, IOException {
        HttpGet httpGet = mHttpApi.createHttpGet(fullUrl(URL_API_TIPS), //
                new BasicNameValuePair("geolat", geolat), //
                new BasicNameValuePair("geolong", geolong), //
                new BasicNameValuePair("geohacc", geohacc), //
                new BasicNameValuePair("geovacc", geovacc), //
                new BasicNameValuePair("geoalt", geoalt), //
                new BasicNameValuePair("uid", uid), //
                new BasicNameValuePair("filter", filter), //
                new BasicNameValuePair("sort", sort), //
                new BasicNameValuePair("l", String.valueOf(limit)) //
                );
        return (Group<Tip>) mHttpApi.doHttpRequest(httpGet, new GroupParser(
                new TipParser()));
    }

    @SuppressWarnings("unchecked")
    Group<User> friendsInTrip(String tripId) throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIP), //
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("trip_id", tripId),
                new BasicNameValuePair("p_act", "focus"));
        return (Group<User>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new UserParser()));
    }

    @SuppressWarnings("unchecked")
    Group<User> friends(String viewUserId) throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FRIENDS), //
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", viewUserId),
                new BasicNameValuePair("p_act", "my_friends"));
        return (Group<User>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new UserParser()));
    }

    @SuppressWarnings("unchecked")
    Group<User> friendRequests() throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FRIEND_REQUESTS),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("p_act", "invite_list"));
        return (Group<User>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new UserParser()));
    }

   Response friendRequestsByEmail(String email) throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_EMAIL_REQUEST),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("email", email),
                new BasicNameValuePair("p_act", "invite"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    Response tripFocusedRequest(String tripId, boolean isFocused)
        throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        String isfocused = "create";
        if (!isFocused)  isfocused = "delete";
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIP_FOCUSED),
                        new BasicNameValuePair("uid", mAuthUserId),
                        new BasicNameValuePair("trip_id", tripId),
                        new BasicNameValuePair("p_act", isfocused));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    Response tripFocusedRequest(String tripId, String followUserId)
    throws PlayLv2ApiException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_TRIP_ADD_FOLLOWED),
                        new BasicNameValuePair("uid", mAuthUserId),
                        new BasicNameValuePair("trip_id", tripId),
                        new BasicNameValuePair("view_uid", followUserId),
                        new BasicNameValuePair("p_act", "invite_friends"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    Response friendApprove(String uid) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FRIEND_SENDREQUEST),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", uid),
                new BasicNameValuePair("p_act", "consort"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    Response friendDeny(String uid) throws PlayLv2ApiException, PlayLv2ApiCredentialsException,
            PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FRIEND_SENDREQUEST),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", uid),
                new BasicNameValuePair("p_act", "ignore"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    Response friendSendrequest(String uid)
        throws PlayLv2ApiException, PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FRIEND_SENDREQUEST),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("view_uid", uid),
                new BasicNameValuePair("p_act", "create"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    /**
     * /findfriends/byname?q=john doe, mary smith
     */
    @SuppressWarnings("unchecked")
    public Group<User> findFriendsByName(String text) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpGet httpGet = mHttpApi.createHttpGet(fullUrl(URL_API_FIND_FRIENDS_BY_NAME), //
                new BasicNameValuePair("q", text));
        return (Group<User>) mHttpApi.doHttpRequest(httpGet, new GroupParser(new UserParser()));
    }

    @SuppressWarnings("unchecked")
    public Group<User> findFriendsByInput(String text) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FIND_FRIENDS_BY_INPUT),
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("srch_account", text),
                new BasicNameValuePair("p_act", "list"));
        return (Group<User>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new UserParser()));
    }

    @SuppressWarnings("unchecked")
    public Group<User> findFriendsByPhone(String text) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FIND_FRIENDS_BY_PHONE), //
                new BasicNameValuePair("q", text));
        return (Group<User>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new UserParser()));
    }

    /**
     * /categories
     */
    @SuppressWarnings("unchecked")
    public Group<VenueCategory> categories() throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpGet httpGet = mHttpApi.createHttpGet(fullUrl(URL_API_CATEGORIES));
        return (Group<VenueCategory>) mHttpApi.doHttpRequest(httpGet, new GroupParser(new VenueCategoryParser()));
    }

    /**
     * /history
     */
    @SuppressWarnings("unchecked")
    public Group<Checkin> history(String limit, String sinceid) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpGet httpGet = mHttpApi.createHttpGet(fullUrl(URL_API_HISTORY),
            new BasicNameValuePair("l", limit),
            new BasicNameValuePair("sinceid", sinceid));
        return (Group<Checkin>) mHttpApi.doHttpRequest(httpGet, new GroupParser(new CheckinParser()));
    }

    /**
     * /tip/detail?tid=1234
     */
    public Tip tipDetail(String tid) throws PlayLv2ApiException,
        PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpGet httpGet = mHttpApi.createHttpGet(fullUrl(URL_API_TIP_DETAIL), //
                new BasicNameValuePair("tid", tid));
        return (Tip) mHttpApi.doHttpRequest(httpGet, new TipParser());
    }

    /**
     * /findfriends/byphoneoremail?p=comma-sep-list-of-phones&e=comma-sep-list-of-emails
     */
    public FriendInvitesResult findFriendsByPhoneOrEmail(String phones, String emails) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_FIND_FRIENDS_BY_PHONE_OR_EMAIL), //
                new BasicNameValuePair("p", phones),
                new BasicNameValuePair("e", emails));
        return (FriendInvitesResult) mHttpApi.doHttpRequest(httpPost, new FriendInvitesResultParser());
    }

    /**
     * /invite/byemail?q=comma-sep-list-of-emails
     */
    public Response inviteByEmail(String emails) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_INVITE_BY_EMAIL), //
                new BasicNameValuePair("q", emails));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    /**
     * /settings/setpings?self=[on|off]
     */
    public Settings setpings(boolean on) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_SETPINGS), //
                new BasicNameValuePair("self", on ? "on" : "off"));
        return (Settings) mHttpApi.doHttpRequest(httpPost, new SettingsParser());
    }

    /**
     * /settings/setpings?uid=userid
     */
    public Settings setpings(String userid, boolean on) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_SETPINGS), //
                new BasicNameValuePair(userid, on ? "on" : "off"));
        return (Settings) mHttpApi.doHttpRequest(httpPost, new SettingsParser());
    }

    /**
     * /venue/flagclosed?vid=venueid
     */
    public Response flagclosed(String venueId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_VENUE_FLAG_CLOSED), //
                new BasicNameValuePair("vid", venueId));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    /**
     * /venue/flagmislocated?vid=venueid
     */
    public Response flagmislocated(String venueId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_VENUE_FLAG_MISLOCATED), //
                new BasicNameValuePair("vid", venueId));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    /**
     * /venue/flagduplicate?vid=venueid
     */
    public Response flagduplicate(String venueId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_VENUE_FLAG_DUPLICATE), //
                new BasicNameValuePair("vid", venueId));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    /**
     * /venue/prposeedit?vid=venueid&name=...
     */
    public Response proposeedit(String venueId, String name, String address, String crossstreet,
            String city, String state, String zip, String phone, String categoryId, String geolat,
            String geolong, String geohacc, String geovacc, String geoalt) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_VENUE_PROPOSE_EDIT), //
                new BasicNameValuePair("vid", venueId), //
                new BasicNameValuePair("name", name), //
                new BasicNameValuePair("address", address), //
                new BasicNameValuePair("crossstreet", crossstreet), //
                new BasicNameValuePair("city", city), //
                new BasicNameValuePair("state", state), //
                new BasicNameValuePair("zip", zip), //
                new BasicNameValuePair("phone", phone), //
                new BasicNameValuePair("primarycategoryid", categoryId), //
                new BasicNameValuePair("geolat", geolat), //
                new BasicNameValuePair("geolong", geolong), //
                new BasicNameValuePair("geohacc", geohacc), //
                new BasicNameValuePair("geovacc", geovacc), //
                new BasicNameValuePair("geoalt", geoalt) //
                );
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    @SuppressWarnings("unchecked")
    public Group<Message> messages(boolean isInbox) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        String folder = (isInbox == true)?"receive":"system";
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_MESSAGES), //
                new BasicNameValuePair("uid", mAuthUserId),
                new BasicNameValuePair("type", folder),
                new BasicNameValuePair("p_act", "list"));
        return (Group<Message>) mHttpApi.doHttpRequest(httpPost, new GroupParser(new MessageParser()));
    }

    public Response deleteMsg(String msgId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_MESSAGE), //
            new BasicNameValuePair("uid", mAuthUserId),
            new BasicNameValuePair("pm_id", msgId),
            new BasicNameValuePair("p_act", "delete"));
        return (Response) mHttpApi.doHttpRequest(httpPost, new ResponseParser());
    }

    public Message getMsgContent(String msgId) throws PlayLv2ApiException,
            PlayLv2ApiCredentialsException, PlayLv2ApiError, IOException {
        HttpPost httpPost = mHttpApi.createHttpPost(fullUrl(URL_API_MESSAGES), //
            new BasicNameValuePair("uid", mAuthUserId),
            new BasicNameValuePair("pm_id", msgId),
            new BasicNameValuePair("p_act", "detail"));
        return (Message) mHttpApi.doHttpRequest(httpPost, new MessageParser());
    }

    private String fullUrl(String url) {
        return mApiBaseUrl + url;
    }

    public Response photoUpdate(String imagePath, String imageExt, boolean isUserPhotoUpdate)
        throws SocketTimeoutException, IOException, PlayLv2ApiError, PlayLv2ApiParseException {

        File file = new File(imagePath);
        FileInputStream fileInputStream = new FileInputStream(file);
        int maxBufferSize = 8192;
        String serverUrl = (isUserPhotoUpdate == true)?
                String.format(URL_API_USER_PHOTO_UPDATE, mAuthUserId, imageExt):
                String.format(URL_API_PHOTO_UPLOAD, mAuthUserId, imageExt);
        URL url = new URL(fullUrl(serverUrl));
        HttpURLConnection conn = mHttpApi.createHttpURLConnectionPost(url);

        DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
        int bytesAvailable = fileInputStream.available();
        int bufferSize = Math.min(bytesAvailable, maxBufferSize);
        byte[] buffer = new byte[bufferSize];

        int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        int totalBytesRead = bytesRead;
        while (bytesRead > 0) {
            dos.write(buffer, 0, bufferSize);
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            totalBytesRead = totalBytesRead  + bytesRead;
        }
        fileInputStream.close();
        dos.flush();
        dos.close();

        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuilder response = new StringBuilder();
        String responseLine = "";
        while ((responseLine = in.readLine()) != null) {
            response.append(responseLine);
        }
        in.close();

        try {
            return (Response)JSONUtils.consume(new ResponseParser(), response.toString());
        } catch (Exception ex) {
            throw new PlayLv2ApiParseException(
                    "Error parsing user photo upload response, invalid json.");
        }
    }

    public Response photoUpdate2(Bitmap bmp)
        throws SocketTimeoutException, IOException, PlayLv2ApiError, PlayLv2ApiParseException {

        String serverUrl =  String.format(URL_API_PHOTO_UPLOAD, mAuthUserId, "jpg");
        URL url = new URL(fullUrl(serverUrl));
        HttpURLConnection conn = mHttpApi.createHttpURLConnectionPost(url);

        DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        dos.write(baos.toByteArray(), 0, baos.size());
        dos.flush();
        dos.close();

        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuilder response = new StringBuilder();
        String responseLine = "";
        while ((responseLine = in.readLine()) != null) {
            response.append(responseLine);
        }
        in.close();

        try {
            return (Response)JSONUtils.consume(new ResponseParser(), response.toString());
        } catch (Exception ex) {
            throw new PlayLv2ApiParseException(
                    "Error parsing user photo upload response, invalid json.");
        }
    }
}
